package com.imooc.aspect;

import com.imooc.annoations.AccessLimit;
import com.imooc.redis.RedisService;
import com.imooc.redis.UserKey;
import com.imooc.utils.MapUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * Created by MisterDeng on 2018/5/17/017 11:53.
 */
@Aspect
@Component
@Slf4j
public class BuyerAuthorizeAspect {
    @Autowired
    private RedisService redisService;

    @Pointcut("execution(public * com.imooc.controller.Buyer*.*(..))")
    public void verify() {}

    @Before("verify()")
    public void doVerify(JoinPoint point) throws Exception {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        // request
        HttpServletRequest request = attributes.getRequest();
        MethodSignature ms = (MethodSignature) point.getSignature();
        Method method = ms.getMethod(); // 获取方法
        AccessLimit limit = method.getAnnotation(AccessLimit.class); // 获取注解
        Map<String, Object> args = MapUtil.objectToMap(point.getArgs()[0]); // 获取参数

        if (limit==null) { // 没有limit注解
            return;
        }
        // 唯一标识
        String key = request.getRequestURI();
        if (limit.field()!=null) { // 针对字段限制
            if (args.get(limit.field()) == null) {
                return; // 如果字段不存在不做限制
            } else  {
                String fieldValue = (String) args.get(limit.field());
                key += "_" + fieldValue;
            }
        }

        UserKey prefix = UserKey.limitWithExpire(limit.second()); // redis设置过期时间的key
        Integer count = redisService.get(prefix, key, Integer.class); // 使用Integer因为可能为null
        if (count==null) {
            redisService.set(prefix, key, 1);
            return;
        } else if (count<limit.maxCount()) {
            redisService.incr(prefix, key);
            return;
        } else {
            throw new RuntimeException("请求次数过多啦");
        }

    }
}
